#from __future__ import print_function

from django.db import models
#from django.contrib.auth.models import User
import sys

from string import lower
from collections import defaultdict
from psd.register.psdcheckbox import MatchQuestion, MatchChoice, getPSDCheckboxOptions, get_preference_for, genCodeForSeekAndPrefs, genSeekAndPrefs
from django.core.exceptions import ObjectDoesNotExist

import logging
logger = logging.getLogger('psd.register.models')


    
    
def csv_to_set(s):
    """
    >>> csv_to_set('a,b')
    set(['a', 'b'])
    >>> csv_to_set('')
    set([])
    """
    return set(s.split(',') if s else [])


def getReadableStringFromMatchQuestion( obj, match_question, tagFunction, conjunction="and" ):
        """
        tagFunction is a function that takes a matchchoice code and returns boolean value of whether
        self has checked that box or not.  E.g., atLoc.
        
        It can also take a function that returns a 0,1,2 weight, in which case the 2 weights
        are marked with a "*" to denote extra interest.  E.g., prefG
        """
        hits = []
        for tup in match_question:
            val = tagFunction( obj, tup[0] )
            if val==2:
                hits.append( tup[1] + "*" )
            elif val:
                hits.append( tup[1] )
    
        
        if len(hits) == 0:
            return ""
        elif len(hits) == 1:
            return hits[0]
        elif len(hits) == 2:
            return hits[0] + " " + conjunction + " " + hits[1]
        else:
            ss = hits[0]
            for lo in hits[1:-1]:
                ss = ss + ", " + lo
            
            ss = ss + ", " + conjunction + " " + hits[-1]
               
            return ss
        
        


class Person(models.Model):
    
    GENDERS = None
    
    first_name = models.CharField(max_length=30, verbose_name="First Name")
    last_name = models.CharField(max_length=30, verbose_name="Last Name")
    gender = models.CharField(max_length=20, verbose_name="Gender")
    age = models.PositiveIntegerField(verbose_name="Age")
    seeking_primary = models.BooleanField(verbose_name="Seeking Primary (Y/N)")
    kinky = models.BooleanField(verbose_name="Kinky (Y/N)")
    seek_gender = models.CharField(max_length=30, verbose_name="Genders Sought")
    
    seek_age_min = models.PositiveIntegerField(verbose_name="Minimum Age Wanted")
    seek_age_max = models.PositiveIntegerField(verbose_name="Maximum Age Wanted")
    seek_kinkiness = models.CharField(max_length=2, verbose_name="Kinkiness Wanted")
    psdid = models.CharField(max_length=6, blank=True) # unique=TRUE


    def genderOptions(self):
        """
        This should be a class method. 
        Fetch list of locations from database and stash in local variable to avoid
        making too many database hits.
        """
        if Person.GENDERS == None:
            print( "Loading gender options and setting GENDER variable in Person" )
            logger.debug( "Loading gender options and setting GENDER variable in Person" )
            Person.GENDERS = getPSDCheckboxOptions( "Gender" )
            #logger.debug( "Got " + str( Person.GENDERS ) )
        return Person.GENDERS



    def __unicode__(self):
        return self.first_name + ' ' + self.last_name

    @property
    def gender_set(self):
        res = csv_to_set(self.gender)
        return res

    @property
    def seek_gender_set(self):
        res = genSeekAndPrefs(self.seek_gender)[0]
        return set(res)

    @property
    def pref_gender_set(self):
        res = genSeekAndPrefs(self.seek_gender)[1]
        return set(res)
    
    def interest_score(self, other):
        if self.will_date(other):
            return 1 + self.bonus_for(other)
        else:
            return 0

    @property
    def will_date_kinky(self):
        return self.seek_kinkiness in ('K','EI')


    @property
    def will_date_nonkinky(self):
        return self.seek_kinkiness in ('NK','EI')


    def kink_works_out(self, other):
        # Testing out the theory that vanilla people shouldn't be able
        # to reject kinky people out of hand.
        #
        # So, this aspect of the match is okay unless:
        # - I am kinky, AND
        # - other is not kinky, AND
        # - I am not okay with that
        #return not (self.kinky and not other.kinky and not self.will_date_nonkinky)
        return (other.kinky and self.will_date_kinky) or (not other.kinky and self.will_date_nonkinky)

    def mutual(self, other):
        return self.will_date(other) and other.will_date(self)

    def will_date(self, other):
        return (
            other.gender_set.issubset(self.seek_gender_set) and 
            other.age >= self.seek_age_min and 
            other.age <= self.seek_age_max and 
            self.kink_works_out(other) and
            self.psdid != other.psdid
                )

    def bonus_for(self, other):
        bonus = 0
        if other.age >= self.seek_age_min+5 and \
           other.age <= self.seek_age_max-5:
            bonus += 2
            
        if self.kinky == other.kinky:
            bonus += 2
            
        if self.seeking_primary and other.seeking_primary:
            bonus += 2

        if len( self.pref_gender_set.intersection(other.gender_set) ) > 0:
            bonus += 2
            
        return bonus

    def mutual_with_any(self, group):
        return any(self.mutual(o) for o in group.members)

    def isG(self,gen):
        if gen in csv_to_set(self.gender):
            return True
        else:
            return False

    def lookG(self,gen):
        gs = self.seek_gender_set
        if gen in gs:
            return True
        else:
            return False

    def prefG(self,gen):
        return get_preference_for( self.seek_gender, gen ) > 1
        
            
    def genderDesc(self):
        ss = getReadableStringFromMatchQuestion( self, self.genderOptions(), Person.isG )
        if ss == "":
            return "No preference given (so anyone could match)"
        else:
            return ss

        return ss.strip()

    def genderLookDesc(self):
        try:
            ss = getReadableStringFromMatchQuestion( self, self.genderOptions(), Person.lookG, conjunction="or" )
            if ss == "":
                return "nothing (which will prevent all matches)"
            else:
                return ss
            return ss.strip()
        except Exception as inst:
            print "Caught error"
            print inst
            print "ouch"
            
        return "FAILED in genderLookDesc()"
    
    def genderPrefDesc(self):
        try:
            ss = getReadableStringFromMatchQuestion( self, self.genderOptions(), Person.prefG, conjunction="and" )
            if ss == "":
                return ""
            else:
                return ss
            return ss.strip()
        except Exception as inst:
            print "Caught error"
            print inst
            print "ouch"
            
        return "FAILED in genderPrefDesc()"



    def miniCode( self ):
        """Short string to describe person's dating characteristics"""
        s = str(self.age) + ' ' + self.gender.replace(",","/") + ' '
        if self.kinky:
           s = s + "k"
            
        if self.seeking_primary:
           s = s + "p"
        s = s + " -> " + str(self.seek_age_min) + "-" + str(self.seek_age_max) \
                         + ' ' + self.seek_gender.replace(",","/") + ' ' + lower(self.seek_kinkiness[0]) 
        return s#.tolower()



    def yourGeekCode( self, sayPrimaryStatus=True ):
        try:
            s = ""
            if self.kinky:
                s = "a kinky " + str(self.age) + " year old"
            else:
                s = "a not-kinky " + str(self.age) + " year old"
                            
            if sayPrimaryStatus:
                 if self.seeking_primary:
                    s += ", potentially interested in a primary,"
                 else:
                    s += ""
    
            s += " looking for " + str(self.seek_age_min) + "-" + str(self.seek_age_max) + " yr old"
    
            if self.seek_kinkiness == 'K':
                s += " kinky " + self.genderLookDesc()
            elif self.seek_kinkiness == 'NK':
                s += " non-kinky " + self.genderLookDesc()
            elif self.seek_kinkiness == 'EI':
                s += " " + self.genderLookDesc()
            s += "."
            gp = self.genderPrefDesc() 
            if ( len(gp) > 0 ):
                gp = gp[0].capitalize() + gp[1:]
                s += "  " + gp + " are preferred."
            if sayPrimaryStatus:
                s+="\n\n"
            else:
                s+="  "
                
            s += "Your dates must be willing to date all of the following: " + self.genderDesc() + "."
            
            return s
        except Exception as inst:
            print "Caught error"
            print inst
            print "ouch"
            print "yourGeekCode() for person failed"
            return "ERROR some person or other"



    def geekCode( self, sayPrimaryStatus=True ):
        try:
            s = ""
            if self.kinky:
                s = "a kinky " + str(self.age) + " yr old"
            else:
                s = "a not-kinky " + str(self.age) + " yr old"
           
            # + self.genderDesc()
            #logger.debug( "geekCode called for %s" % (self.psdid, ) )
            if sayPrimaryStatus:
                 if self.seeking_primary:
                    s += ", potentially interested in a primary,"
                 else:
                    s += ""
    
            s += " looking for " + str(self.seek_age_min) + "-" + str(self.seek_age_max) + " yr old"
    
            if self.seek_kinkiness == 'K':
                s += " kinky " + self.genderLookDesc()
            elif self.seek_kinkiness == 'NK':
                s += " non-kinky " + self.genderLookDesc()
            elif self.seek_kinkiness == 'EI':
                s += " " + self.genderLookDesc()
    
            s += ".  Dates must be willing to date " + self.genderDesc()
            return s
        except:
            print "geekCode() for person failed"
            return "ERROR some person or other"


#    def pronoun(g):
#        if not isinstance(g, list):
#            g = g.split(',')
#        if 'Q' in g or ('ME' in g and 'WO' in g) or ('TM' in g and 'TW' in g): return "Zie"
#        elif 'TM' in g: return "He"
#        elif 'TW' in g: return "She"
#        elif 'ME' in g: return "He"
#        elif 'WO' in g: return "She"
#        else: return "Zie"
#        ## This last case should be impossible, but...


#    def long_gender(self, plural=False):
#        g = self.gender
#        names = {'ME': ('man', 'men'),
#                 'WO': ('woman', 'women'),
#                 'TM': ('transman', 'transmen'),
#                 'TW': ('transwoman', 'transwomen'),
#                 'Q': ('genderqueer', 'genderqueers')}
#        if not isinstance(g, list):
#            g = g.split(',')
#        ## Use sets here in case order is somehow scrambled.
#        if set(g) == set(names):
#            return "people of any gender" if plural else "person of all genders"
#        else:
#            ## Because we are bad people, we will use the fact that
#            ## you can treat bools as ints with True == 1 and False == 0.
#            return '/'.join(names[x][plural] for x in g)

    @property
    def fullname(self):
        return self.first_name + " " + self.last_name



class RegRecord(models.Model):
    LOCATION = None
    
    nickname = models.CharField(max_length=30, verbose_name="Nickname")
    email = models.EmailField(verbose_name="Email")
    add_to_mailings = models.BooleanField(default=True, verbose_name="Join Our Mailing List (Y/N)")
    seek_groups = models.BooleanField(verbose_name="Date Groups (Y/N)")
    seek_fling = models.CharField(max_length=2, verbose_name="Fling Wanted")
    groups_match_all = models.BooleanField(verbose_name="All Group Members Must Match (Y/N)")
    #only_groups = models.BooleanField( verbose_name="Only Date Groups if Dating Groups (Y/N)" )
    friend_dates = models.BooleanField(verbose_name="Friend Dates (Y/N)")
    referred_by = models.CharField(max_length=100, blank=True, verbose_name="Referred By")
    pals = models.TextField(blank=True, verbose_name="Friends")
    location = models.CharField(max_length=100, blank=True, verbose_name="Location")
    wants_childcare = models.BooleanField(verbose_name="Need Childcare (Y/N)")
    children = models.TextField(blank=True, verbose_name="Children")
    comments = models.TextField(blank=True, verbose_name="Comments")
    event = models.CharField(max_length=10, blank=True)
    people = models.ManyToManyField(Person, blank=True)
    #user = models.OneToOneField(User, null=True, blank=True)
    psdid = models.CharField(max_length=7, blank=True) # 7 for triads
    paid = models.BooleanField(default=False)
    cancelled = models.BooleanField(default=False)
    pending = models.BooleanField(default=False)
    here = models.BooleanField(default=False)
    stationary = models.BooleanField(default=False)
    is_group = models.BooleanField(default=False)
    notes = models.TextField(blank=True)
    matches = models.IntegerField(blank=True, null=True, default=0)
    oneway = models.IntegerField(blank=True, null=True, default=0)
  
    @property
    def members(self):
        return self.people.all()

    @property
    def size(self):
        return self.people.count()

    def atLoc(self,loc):
        gs = csv_to_set(self.location)
        if loc in gs:
            return True
        else:
            return False

    @property
    def will_date_fling(self):
        return self.seek_fling in ('K','EI')

    @property
    def will_date_nonfling(self):
        return self.seek_fling in ('NK','EI')

    def fling_works_out(self, other):
        return (self.will_date_fling and other.will_date_fling) or \
            (self.will_date_nonfling and other.will_date_nonfling )
             

    def miniCode( self ):
        """Short string to describe record's dating characteristics"""

        numPeeps = self.size

        if not self.is_group:
            s = self.indiv.miniCode()
        else:
            peeps = self.members
            s = peeps[0].miniCode()
            for p in peeps[1:]:
                    s += "; " + p.miniCode()

            if self.groups_match_all:
                s += "-all"

        if not self.seek_groups:
            s += ""
        elif self.groups_match_all:
            s += "-all"
        else:
            s += "-any"

        if self.friend_dates:
            s += "-F"

        if self.stationary:
            s += "(S)"
        
        s += "-fl:" + str( self.seek_fling)
        
        s += ' ' + self.location.replace(",","/")
        
        return s
        
        
   
    
    def locationOptions(self):
        """
        This should be a class method. 
        Fetch list of locations from database and stash in local variable to avoid
        making too many database hits.
        """
        
        if RegRecord.LOCATION == None:
            logger.debug( "Loading location options and setting LOCATION variable in regrecord" )
            RegRecord.LOCATION = getPSDCheckboxOptions( "Location" )
            #logger.debug( "Got " + str( RegRecord.LOCATION ) )
        return RegRecord.LOCATION



    def old_geekCode( self ):
        try:
            numPeeps = self.size
    
            if not self.is_group:
                s = self.indiv.geekCode( True )
            else:
                peeps = self.members
                s = "a group of " + peeps[0].geekCode(False)
                for  p in peeps[1:]:
                        s += " and " + p.geekCode(False)
    
                if not self.groups_match_all:
                    s += ". Matching one member is fine"
                else:
                    s += ". All members must match"
    
            s += "."
    
            if not self.seek_groups:
                s += "  Groups not okay."
            elif self.groups_match_all:
                s += "  Groups okay if all match."
            else:
                s += "  Individuals in groups okay."
    
            if self.friend_dates:
                s += "  Friendship dates okay."
            else:
                s += "  No friendship dates."
    
            if self.stationary:
                s += "  Needs to stay in same spot."
    
            try:
                ss = getReadableStringFromMatchQuestion( self, self.locationOptions(), RegRecord.atLoc )
                if ss == "":
                    s += " No residence given."
                else:
                    s += "  From " + ss + "."
            except Exception as inst:
                print "Unexpected error:", sys.exc_info()[0]     
                print type(inst)     # the exception instance
                print inst.args      # arguments stored in .args
                print inst           # __str__ allows args to printed directly                print "location paste failed"
                s += "  From (location lookup fail)"
            except:
                print "Really weird error --- help!"
                
            return s
        except:
            print "geekcode() regrecord failed"
            return "error-some dating group or other"


    def yourGeekCode( self, html=False ):
        try:
            numPeeps = self.size
            
            if not self.is_group:
                s = "You are " + self.indiv.yourGeekCode( True )
            else:
                peeps = self.members
                s = "You all are a group of the following " + str(numPeeps) + " people:\n1) " + peeps[0].yourGeekCode(False)
                for  (k,p) in enumerate( peeps[1:] ):
                        s += "\n%s) %s" % (k+2, p.yourGeekCode(False))
    
                if not self.groups_match_all:
                    s += "\n\nHaving dates that match only one of you is fine."
                else:
                    s += "\n\nDates must be compatible with all of you."
    
            s += "\n\n"
    
            if not self.seek_groups:
                s += "You are not interested in dating groups."
            elif self.groups_match_all:
                if numPeeps > 1:
                    s += "You are interested in dating groups if everyone in each group is compatible with someone in the other group."
                else:
                    s += "You are interested in dating groups if you match everyone in the group."
            else:
                s += "You are interested in dating groups if you match at least one person in the group."
                 
            if self.friend_dates:
                s += "  Friendship dates are okay."
            else:
                s += "  You do not want friendship dates."
    
            if self.stationary:
                s += "  You need to stay in the same spot."
    
            if not self.will_date_nonfling:
                s += "  Only interested in flings."
            elif not self.will_date_fling:
                s += "  Not interested in flings." 
            else:
                s += "  Flings or longer romance okay."
                
            try:
                ss = getReadableStringFromMatchQuestion( self, self.locationOptions(), RegRecord.atLoc, conjunction="or" )
                if ss == "":
                    s += " No residence given."
                else:
                    s += "  We will try to match you with people from " + ss + "."
            except Exception as inst:
                print "Unexpected error:", sys.exc_info()[0]     
                print type(inst)     
                print inst.args      
                print inst           
                s += "  From (location lookup fail)"
            except:
                print "Really weird error --- help!"
                
            if html:
                return s.replace( "\n", "<p>" )
            else:
                return s
        except Exception as inst:
            print "Caught error"
            print inst
            print "ouch"
            print "yourGeekcode() regrecord failed"
            return "error-some dating group or other"

    def geekCode( self ):
        return self.yourGeekCode( html=True )


    def hasNotes( self ):
        if self.notes == "":
           return False
        else:
           return True

    def addNote(self, note ):
        """ append note to field """
        if self.hasNotes():
            self.notes = self.notes + "; " + note
        else:
            self.notes = note
        self.save()
        
        
    def __unicode__(self):
        try:
            return "RR(%s) %s-%s-%s" % (self.id, self.event, self.psdid, '+'.join(unicode(s) for s in self.members))
        except:
            logger.error( sys.exc_info()[0] )
            return "[ERROR - Contact Sys Admin]"


    def integrity_ok(self):
        if self.is_group:
            if self.size > 1:
                return False
        else:
            if self.size != 1:
                return False

        return True

    @property
    def indiv(self):
        assert not self.is_group
        assert self.size == 1, self
        return self.members[0]

#    def all_like(self, whom):
#        ''' Do everyone in this group like a person? '''
#        return all(p.will_date(whom) for p in self.people)
#
#    def all_liked_by(self, whom):
#        ''' Is everyone in this group liked by a person? '''
#        return all(whom.will_date(p) for p in self.people)
#
#    def any_like_all(self, other):
#        ''' Does anyone in this group like everyone in another group? '''
#        return any(other.all_liked_by(p)  for p in self.people)

    def any_match_someone(self, other):
        ''' Does anyone in this group mutually match someone in another group? '''
        return any(p.mutual_with_any(other) for p in self.members)

    def all_match_someone(self, other):
        ''' Does everyone in this group mutually match someone in another group? '''
        return all(p.mutual_with_any(other) for p in self.members)

    @property
    def location_set(self):
        return csv_to_set(self.location)

    @property
    def genders(self):
        return set(g for p in self.members for g in p.gender_set)

    @property
    def seek_genders(self):
        return set(g for p in self.members for g in p.seek_gender_set)

    def has_gender(self, g):
        return g in self.genders

    def wants_gender(self, g):
        return g in self.seek_genders

    @property
    def one_cisgender(self):
        sg = self.genders
        return (len(sg) == 1) and (sg[0] in ('ME','WO'))

    @property
    def is_man_only(self):
        return (self.has_gender('ME') or self.has_gender("TM")) and not ( self.has_gender('WO') or self.has_gender('TW') )
 
    @property
    def is_woman_only(self):
        return (self.has_gender('WO') or self.has_gender("TW")) and not ( self.has_gender('ME') or self.has_gender('TM') )

    @property
    def only_alt_gendered(self):
        return (not self.has_gender('ME')) and (not self.has_gender('WO'))

    @property
    def wants_mf(self):
        return (self.wants_gender('ME') or self.wants_gender('TM')) and (self.wants_gender('WO') or self.wants_gender('TW'))

    @property
    def wants_m(self):
        return self.wants_gender('ME') or self.wants_gender('TM')

    @property
    def wants_f(self):
        return self.wants_gender('WO') or self.wants_gender('TW')

    def mf_gender_match(self, other):
        return (self.has_gender('ME') and other.has_gender('ME'))  or \
               (self.has_gender('WO') and other.has_gender('WO'))

    def mf_gender_cross(self, other):
        return (self.has_gender('ME') and other.has_gender('WO'))  or \
               (self.has_gender('WO') and other.has_gender('ME'))

    def location_overlap(self, other):
        return bool(self.location_set & other.location_set)

    def interest_score(self, other):
        score = 1
        if other.is_group and (not self.seek_groups):
            return 0

        if not self.fling_works_out(other):
            return 0
            
        if self.location_overlap(other):
            score += 2

        if self.is_group:
            if self.groups_match_all:
                if not other.is_group:
                    score += 1
                return score if self.all_match_someone(other) else 0
            else:
                return score if self.any_match_someone(other) else 0

        else: # we are an individual
            me = self.indiv
            if other.is_group:
                if self.groups_match_all:
                    if all(me.will_date(o) for o in other.members):
                        return score + \
                            min(me.bonus_for(o) for o in other.members)
                    else:
                        return 0
                else: # only need to match one of them
                    if any(me.will_date(o) for o in other.members):
                        return score + \
                            max(me.bonus_for(o) for o in other.members)
                    else:
                        return 0
            else:
                you = other.indiv
                if not me.will_date(you):
                    return 0
                return score + me.bonus_for(you)

    @property
    def treat_as_man(self):
        return (self.is_group) or self.is_man_only

    @property
    def treat_as_woman(self):
        return not self.treat_as_man


    @property
    def straightish_male(self):
        return self.treat_as_man and not (self.wants_gender("ME") or self.wants_gender("TM"))
    
        
    def ok_gay_match(self, other):
        """ Return true if person is not bi or the match would be a "gay" match"""
        if not self.wants_mf:
            return True
        return (self.treat_as_woman and other.treat_as_woman) or \
               (self.treat_as_man and other.treat_as_man)

  
    def ok_str_match(self, other):
       if not self.wants_mf:
            return True
       return (self.treat_as_woman and other.treat_as_man) or \
               (self.treat_as_man and other.treat_as_woman)
  

    def matrix_score(self, other, matrix_type):
        if ( matrix_type == 'gay' and not self.ok_gay_match( other ) ) \
           or ( matrix_type == 'str' and not self.ok_str_match( other ) ):
            return 0
        
        return self.interest_score(other)
    
    def ok_match(self, other, matrix_type ):
        return self.matrix_score(other,matrix_type) > 0
    
    def all_past_dates(self, exclude_event=None):
        """ Return all past dates person has had (possibly excluding some specified event) """
        if exclude_event == None:
            drs = DateRecord.objects.filter(psdid=self.psdid)
        else:
            drs = DateRecord.objects.filter(psdid=self.psdid).exclude( event=exclude_event)
        drids = set(c.other_psdid for c in drs)
        
        return drids
    
    def all_additionals_old(self):
        """ Return list of all additional folks to not date"""
        from django.db import connection, transaction
        cursor = connection.cursor()

        cursor.execute("SELECT MatchA,MatchB from additionals WHERE MatchA=%s OR MatchB=%s", [self.psdid, self.psdid] )
        psdids = cursor.fetchall()
        psdids = set(c[c[0]==self.psdid] for c in psdids)
        return psdids

    def all_additionals(self):
        """ Return list of all additional folks to not date"""
        drs = BreakRecord.objects.filter(psdid=self.psdid )
        drids = set(c.other_psdid for c in drs)

        odrs = BreakRecord.objects.filter(other_psdid=self.psdid)
        drids ^= set(c.psdid for c in odrs)

        return drids
        
    @property
    def namestring(self):
        pnames = ', '.join( c.fullname for c in self.members )
        return self.nickname + ": " + pnames
    
    
def fetch_regrecord( event_name, psdid ):
    """ Get a regrecord, if there is one """
    try:
         per = RegRecord.objects.get( event=event_name, psdid=psdid )
         return per
    except ObjectDoesNotExist:
        logger.error( "Failed to find RR '%s-%s'." % ( event_name, psdid, ) )
        return None

 
    
class MatchRecord( models.Model ):
    psdid1 = models.CharField(max_length=30, verbose_name="subject's PSDID")
    psdid2 = models.CharField(max_length=30, verbose_name="object's PSDID")
    event = models.CharField(max_length=10, blank=True)
    match = models.PositiveIntegerField(verbose_name="Likability")
    gay_ok = models.BooleanField(verbose_name="Gay Round Okay")
    str_ok = models.BooleanField(verbose_name="Straight Round Okay")
    
#    def __init__(self,event,psdid1,psdid2,match,gay_ok,str_ok):
#        self.psdid1=psdid1
#        self.psdid2=psdid2
#        self.event=event
#        self.match=match
#        self.gay_ok=gay_ok
#        self.str_ok=str_ok
        
    def __unicode__(self):
        return self.psdid1 + "-" + self.psdid2 + ": " + str(self.match) + "/" + str(self.gay_ok) + str(self.str_ok)





class Event(models.Model):
    event = models.CharField( max_length=20 )
    longname = models.CharField( max_length=40 )
    location = models.CharField( max_length= 100 )
    address = models.CharField( max_length=100 )
    locationURL = models.CharField( max_length=100 )
    accessdetails = models.TextField( max_length=200 )
    cost = models.PositiveIntegerField(verbose_name="Cost per person")
    doorcost = models.PositiveIntegerField(verbose_name="Cost per person at door")
    paypal_email = models.EmailField(verbose_name="Email for paypal account")
    info_email = models.EmailField(verbose_name="Email for asking registration questions" )
    mailing_list_url = models.CharField( max_length=100, verbose_name="Link to the mailing list for this event" )
    homepage_url = models.CharField( max_length=100, verbose_name="Link to the home page for this event or event organizers" )
    has_childcare = models.BooleanField( default=False, verbose_name="Childcare will be provided at the event" )
    regclosed = models.BooleanField( default=False, verbose_name="Registration is closed---no additions allowed" )
    regfrozen = models.BooleanField( default=False, verbose_name="Registration is frozen--no updating of registration forms allowed" )
    no_ssm = models.BooleanField( default=False, verbose_name="Single straight men will be asked to bring a gender-balance companion" )
    no_emailing = models.BooleanField( default=False, verbose_name="Do not email update emails or admin log emails (check if there is no internet service)." )
    date = models.DateField()
    starttime = models.TimeField()
    deadlinetime = models.TimeField()
    stoptime = models.TimeField()
    
    def __unicode__(self):
        return self.event + " on " + str(self.date)
    

class DateRecord(models.Model):
    """ 
    This stores dating history.   
    
    There _should be_ pairs of entries where if psdid, other_psdid is in the 
    database, then the reverse should be as well.
    """
    friend_date = models.BooleanField(default=True, verbose_name="Date was a Friendship Date (Y/N)")
    psdid = models.CharField(max_length=6, blank=True)
    other_psdid = models.CharField(max_length=6, blank=True)
    table = models.CharField(max_length=10,blank=True)
    round = models.PositiveIntegerField(verbose_name="Dating Round")
#    event = models.ForeignKey(Event, null=True)
    event = models.CharField( max_length=20 )
    said_yes = models.NullBooleanField(default=True, verbose_name="psdid said YES to other_psdid (Y/N)", null=True )
    they_said_yes = models.NullBooleanField(default=True, verbose_name="other_psdid said YES to psdid (Y/N)", null=True )
    notes = models.TextField(blank=True,null=True)

    def is_mutual(self):
        if self.said_yes==None or self.they_said_yes==None:
             return None
        elif self.said_yes and self.they_said_yes:
             return True
        else:
             return False

    @property
    def filled(self):
        return self.said_yes != None and self.they_said_yes != None
    
    
    def __unicode__(self):
        if self.said_yes==None:
             if self.they_said_yes==None:
                ss = " ?/?"
             elif self.they_said_yes:
                ss = " ?/yes"
             else:
                ss = " ?/no"

             if self.friend_date:
                 ss = ss + " (F)"
             return "%s dating %s - %s" % (self.psdid, self.other_psdid, ss, )
        else:
             ss = ""
             if self.said_yes:
                 if self.they_said_yes==None:
                     ss = "yes/?"
                 elif self.they_said_yes:
                     ss = "mutual"
                 else:
                     ss = "yes/no"
             else:
                 if self.they_said_yes==None:
                     ss = "no/?"
                 elif self.they_said_yes:
                     ss = "no/yes"
                 else:
                     ss = "no/no"

             if self.friend_date:
                 ss = ss + " (F)"
             return "%s dating %s - %s" % (self.psdid, self.other_psdid, ss)
         
       
class TableListRecord(models.Model):
    event = models.CharField(max_length=12, blank=True)

    def __unicode__(self):
        #numtabs = len( self.group_set.all() )
        #s = "List for %s (%s tables)" % (self.event, numtabs)
        s = "List for %s" % (self.event,)
        return s
        
class TableRecord(models.Model):
    name = models.CharField(max_length=12, blank=True)
    statOK = models.BooleanField(default=False, verbose_name="Okay for stationary folks (Y/N)")
    groupOK =  models.BooleanField(default=False, verbose_name="Okay for groups (Y/N)")
    quality = models.PositiveIntegerField(verbose_name="Quality")
    group = models.ForeignKey(TableListRecord)
    
    def __unicode__(self):
        s = "%s/%s - %s" % ( self.group.event, self.name, self.quality )
        if self.statOK:
            s += "/stat"
        if self.groupOK:
            s += "/grp"
        return s

    
    
class BreakRecord(models.Model):
    """ 
    This stores a hand-break (i.e., two people who should not be seated
    next to each other)   
    
    There does not need to be symmetry in these (i.e. pairs of entries where 
    if psdid, other_psdid is in the 
    database, then the reverse should be as well.)
    """
    friend_ok = models.BooleanField(default=False, verbose_name="Friendship Date Still Okay (Y/N)")
    psdid = models.CharField(max_length=6, blank=True)
    other_psdid = models.CharField(max_length=6, blank=True)
    notes = models.TextField(blank=True)

    def __unicode__(self):
        return "%s X %s - %s" % ( self.psdid, self.other_psdid, self.notes )
    

class CruiseRecord(models.Model):
    """
    This stores a cruise (i.e. one person wants their info sent
    unilaterally to another person).
    """
    psdid = models.CharField(max_length=7, blank=True)
    other_psdid = models.CharField(max_length=7, blank=True)
    event = models.CharField( max_length=20 )

    def __unicode__(self):
        return "%s cruised %s at %s" % (self.psdid, self.other_psdid, self.event)


class LinkRecord(models.Model):
    """
    This registers that psdid should not date anyone that psdid_alias has dated
    """
    psdid = models.CharField(max_length=7, blank=True)
    psdid_alias = models.CharField(max_length=7, blank=True)
 
    def __unicode__(self):
        return "%s takes history from %s" % (self.psdid, self.psdid_alias,)

class RecessRecord(models.Model):
    """
    This means the given psdid has mandatory free time during the given
    rounds of the given event. Can also have the special psdid "template".
    The 'volatile' field should be set to False for hand-added recesses
    (e.g. a person has said they need to leave early).
    """
    psdid = models.CharField(max_length=8, blank=True)
    event = models.CharField(max_length=20)
    rounds = models.CharField(max_length=10)
    kind = models.CharField(max_length=20)
    volatile = models.BooleanField(default=True)

    def __unicode__(self):
        return "Recess for %s at %s: rounds %s '%s'" % (self.psdid, self.event, self.rounds, self.kind)
